package com.github.thinwonton.seckill.service.impl;

import java.util.Date;
import java.util.List;

import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.thinwonton.seckill.dao.SeckillDao;
import com.github.thinwonton.seckill.dao.SuccessKilledDao;
import com.github.thinwonton.seckill.entity.enums.SuccessKilledState;
import com.github.thinwonton.seckill.entity.po.Seckill;
import com.github.thinwonton.seckill.entity.po.SuccessKilled;
import com.github.thinwonton.seckill.entity.web.Exposer;
import com.github.thinwonton.seckill.entity.web.SeckillExecution;
import com.github.thinwonton.seckill.exception.SeckillClosedException;
import com.github.thinwonton.seckill.exception.SeckillException;
import com.github.thinwonton.seckill.exception.SeckillIllegalRequestException;
import com.github.thinwonton.seckill.exception.SeckillRepeateException;
import com.github.thinwonton.seckill.service.SeckillService;

@Service
public class SeckillServiceImpl implements SeckillService {

	/**
	 * MD5加密的盐
	 */
	private String salt = "$1$HjKEo";

	@Autowired
	private SeckillDao seckillDao;

	@Autowired
	private SuccessKilledDao successKilledDao;

	@Override
	public List<Seckill> getSeckillList() {
		return seckillDao.list();
	}

	@Override
	public Seckill getById(long seckillId) {
		if (seckillId > 0) {
			return seckillDao.selectByPrimaryKey(seckillId);
		}
		return null;
	}

	@Override
	public Exposer expose(long seckillId) {
		if (seckillId <= 0) {
			return new Exposer(seckillId, false, null, null, null, null);
		}

		// 验证秒杀商品是否存在
		Seckill seckill = getById(seckillId);
		if (seckill == null) {
			return new Exposer(seckillId, false, null, null, null, null);
		}

		// 验证秒杀时间
		Date now = new Date();
		if (now.getTime() < seckill.getStartTime().getTime() || now.getTime() >= seckill.getEndTime().getTime()) {
			return new Exposer(seckillId, false, null, seckill.getStartTime(), seckill.getEndTime(), now);
		}

		String secretKey = md5(seckill.getId());

		return new Exposer(seckillId, true, secretKey, seckill.getStartTime(), seckill.getEndTime(), now);
	}

	private String md5(Long seckillId) {
		return Md5Crypt.md5Crypt(String.valueOf(seckillId).getBytes(), salt);
	}

	@Transactional
	@Override
	public SeckillExecution execute(long seckillId, String secretKey, long userid)
			throws SeckillClosedException, SeckillRepeateException, SeckillException {

		try {
			if (secretKey == null || !secretKey.equals(md5(seckillId))) {
				throw new SeckillIllegalRequestException("非法参数");
			}

			// 减库存
			int updateCount = seckillDao.reduceNumber(seckillId);
			if (updateCount > 0) {
				// 减库存成功，记录购买行为
				SuccessKilled record = new SuccessKilled();
				record.setState((byte) SuccessKilledState.SUCCESS.getState());
				record.setSeckillId(seckillId);
				record.setUserId(userid);
				int insertCount = successKilledDao.insertSelective(record);

				if (insertCount > 0) {
					// 秒杀成功
					return new SeckillExecution(true, "秒杀成功");
				} else {
					// 重复秒杀
					throw new SeckillRepeateException("重复秒杀");
				}

			} else {
				// 减库存失败，秒杀结束
				throw new SeckillClosedException("秒杀结束");
			}
		} catch (SeckillException e) {
			throw e;
		} catch (Exception e1) {
			throw new SeckillException("seckill inner error:" + e1.getMessage());
		}

	}

}